/*
 * Copyright (c) 2022, yifengling0. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. No personal names or organizations' names associated with the
 *    Atomthreads project may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "atom.h"
#include "iosdrv.h"
#include "rtc.h"
#include "debug.h"
#include "console.h"
#include <string.h>
#include "numberical.h"

int RtcSetDatetime(int year, int month, int day, int hour, int minute, int second)
{
    RtcTime tm_new;
    FD device;
    int ret = NG;

    /* update date. */
    tm_new.tm_year = year - 1900;
    tm_new.tm_mon  = month - 1; /* tm_mon: 0~11 */
    tm_new.tm_mday = day;
    tm_new.tm_hour = hour;
    tm_new.tm_min  = minute;
    tm_new.tm_sec  = second;

    device = open("rtc", 0, 0);
    if (device == ERR_FD)
    {
        return NG;
    }

    /* update to RTC device. */
    ret = ioctl(device, RTC_CTRL_SET_DATETIME, &tm_new);

    return ret;
}

int RtcGetDatetime(int *year, int *month, int *day, int *hour, int *minute, int *second)
{
    int ret = NG;

    RtcTime now;
    FD device = open("rtc", 0, 0);
    if (device == ERR_FD)
    {
        return NG;
    }
        /* output current time */
    ret = ioctl(device, RTC_CTRL_GET_DATETIME, &now);

    if( ret == OK){
        *year = now.tm_year + 1900;
        *month = now.tm_mon + 1;
        *day =  now.tm_mday;
        *hour = now.tm_hour;
        *minute =  now.tm_min;
        *second = now.tm_sec;
    }

    return ret;
}

int RtcSetAlarm(RtcWakeAlarm *alarm)
{
    FD device;

    device = open("rtc", 0, 0);
    if (device == ERR_FD)
    {
        return NG;
    }

    /* update to RTC device. */
    return ioctl(device, RTC_CTRL_SET_ALARM, alarm);
}

int RtcGetAlarm(RtcWakeAlarm *alarm)
{
    FD device;

    device = open("rtc", 0, 0);
    if (device == ERR_FD)
    {
        return NG;
    }

    /* update to RTC device. */
    return ioctl(device, RTC_CTRL_GET_ALARM, alarm);
}

void RtcSetWakeUp(RtcWakeUp *wakeup)
{
    FD device;

    device = open("rtc", 0, 0);
    if (device == ERR_FD)
    {
        return;
    }

    /* update to RTC device. */
    ioctl(device, RTC_CTRL_SET_WAKEUP, wakeup);
}

#if defined(COM_USE_CONSOLE) && defined(COM_USE_RTC_CMD)

static enConsoleResult date(int argc, char **argv)
{
    if (argc == 1)
    {
        int year, month, day, hour, minute, second;
        RtcGetDatetime(&year, &month, &day, &hour, &minute, &second);
        KPrintf("%d/%02d/%02d %02d:%02d:%02d\r\n", (uint32_t)year, (uint32_t)month, (uint32_t)day, (uint32_t)hour, (uint32_t)minute, (uint32_t)second);
    }
    else if (argc >= 7)
    {
        /* set time and date */
        uint16_t year;
        uint8_t month, day, hour, min, sec;
        year = StringToInt(argv[1]);
        month = StringToInt(argv[2]);
        day = StringToInt(argv[3]);
        hour = StringToInt(argv[4]);
        min = StringToInt(argv[5]);
        sec = StringToInt(argv[6]);
        if (year > 2099 || year < 2000)
        {
            KPrint("year is out of range [2000-2099]\r\n");
            return CE_PARAM_ERROR;
        }
        if (month == 0 || month > 12)
        {
            KPrint("month is out of range [1-12]\r\n");
            return CE_PARAM_ERROR;
        }
        if (day == 0 || day > 31)
        {
            KPrint("day is out of range [1-31]\r\n");
            return CE_PARAM_ERROR;
        }
        if (hour > 23)
        {
            KPrint("hour is out of range [0-23]\r\n");
            return CE_PARAM_ERROR;
        }
        if (min > 59)
        {
            KPrint("minute is out of range [0-59]\r\n");
            return CE_PARAM_ERROR;
        }
        if (sec > 59)
        {
            KPrint("second is out of range [0-59]\r\n");
            return CE_PARAM_ERROR;
        }
        RtcSetDatetime(year, month, day, hour, min, sec);
    }
    else
    {
        KPrint("please input: date [year month day hour min sec] or date\n");
        KPrint("e.g: date 2018 01 01 23 59 59 or date\n");
    }

    return CE_OK;
}

BGEIN_DEF_CMD(_rtcCmd)
    CMD_DEF(date, "set datetime e.g: date 2018 01 01 23 59 59 or date")
END_DEF_CMD(_rtcCmd)

#endif /* COM_USE_CONSOLE */

void RtcCreate(Rtc *rtc, PFIOCTL ioctl)
{
    rtc->super.popen = NULL;
    rtc->super.pioctl = ioctl;
    rtc->super.pread = NULL;
    rtc->super.pwrite = NULL;
    rtc->super.pclose = NULL;

    IosDrvInstall(&rtc->super, "rtc");

#if defined(COM_USE_CONSOLE) && defined(COM_USE_RTC_CMD)    
    CONSOLE_REG_CMD(_rtcCmd);
#endif    
}
